Categories
Vue 3

Form Validation in a Vue 3 App with Vee-Validate 4 — Async and Cross-Field Validation

Spread the love

Form validation is an important part of any app.

In this article, we’ll look at how to use Vee-Validate 4 in our Vue 3 app for form validation.

Async Validation

We can validate form fields asynchronously with Vee-Validate 4.

For example, we can write:

<template>
  <div>
    <Form @submit="onSubmit">
      <label for="email">Email</label>
      <Field id="email" name="email" :rules="validateEmail" type="email" />
      <ErrorMessage name="email" />

      <button type="submit">Submit</button>
    </Form>
  </div>
</template>

<script>
import { Field, Form, ErrorMessage } from "vee-validate";

const mockApiRequest = (value) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(value === "abc@abc.com");
    }, 1000);
  });
};

export default {
  name: "App",
  components: {
    Field,
    Form,
    ErrorMessage,
  },
  methods: {
    onSubmit(values) {
      alert(JSON.stringify(values, null, 2));
    },
    async validateEmail(value) {
      const result = await mockApiRequest(value);
      return result ? true : "This email is already taken";
    },
  },
};
</script>

We have the mockApiRequest function that returns a promise to simulate async validation.

We use that in the validateEmail method.

If it resolves to true , then the field is valid.

Otherwise, it’s not valid.

Then we pass the method into the rules prop to do the validation.

When we press Submit, validation will be run.

If it’s valid, then the onSubmit method will be run.

Cross-Field Validation

We can add cross-field validation with Vee-Validate 4.

For example, to check if the confirm password field matches the password field, we can write:

<template>
  <div>
    <Form @submit="onSubmit" :validation-schema="schema">
      <div>
        <label for="password">Password</label>
        <Field id="password" name="password" type="password" />
        <ErrorMessage name="password" />
      </div>

      <div>
        <label for="passwordConfirmation">Confirm Password </label>
        <Field
          id="passwordConfirmation"
          name="passwordConfirmation"
          type="password"
        />
        <ErrorMessage name="passwordConfirmation" />
      </div>

      <button type="submit">Submit</button>
    </Form>
  </div>
</template>

<script>
import { Field, Form, ErrorMessage, defineRule } from "vee-validate";
import * as yup from "yup";

defineRule("required", (value) => {
  if (!value) {
    return "This is required";
  }

  return true;
});

defineRule("min", (value, [min]) => {
  if (value && value.length < min) {
    return `Should be at least ${min} characters`;
  }

  return true;
});

defineRule("confirmed", (value, [other]) => {
  if (value !== other) {
    return `Passwords do not match`;
  }

return true;
});

export default {
  name: "App",
  components: {
    Field,
    Form,
    ErrorMessage,
  },
  data: () => {
    const schema = yup.object().shape({
      password: yup.string().min(5).required(),
      passwordConfirmation: yup
        .string()
        .required()
        .oneOf([yup.ref("password")], "Passwords do not match"),
    });

    return {
      schema,
    };
  },
  methods: {
    onSubmit(values) {
      alert(JSON.stringify(values, null, 2));
    },
  },
};
</script>

We called defineRule to define the required and min rules to check that the field has a value filled in and that it has the minimum length required.

The confirmed rule is defined with the other variable to check the value of the other field.

We define the Yup schema in the data method.

The validation rules for the passwordConfirmation rule calls oneOf with yup.ref("password") to check that the value of it matches the value of the password field.

Then we pass in the schema into the validation-schema prop.

Conclusion

We can validate form fields asynchronously and do cross-field validation in our Vue 3 app with Vee-Validate 4.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *